package com.eu.chipin.backend;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

public class ExpenseGraph {
	public LinkedList<Payment> generateDumbExpenseGraph(
			HashMap<Member, Double> b) {
		LinkedList<Payment> payments = new LinkedList<Payment>();
		ValueComparator cmp = new ValueComparator(b);
		TreeMap<Member, Double> t = new TreeMap(cmp);
		t.putAll(b);

		Iterator<Entry<Member, Double>> entries = t.entrySet().iterator();
		Entry<Member, Double> first, last;

		while (!t.isEmpty()) {
			first = t.firstEntry();
			last = t.lastEntry();

			if (first == last || first == null || last == null)
				break;
			if (first.getValue().equals(0d)) {
				t.remove(first.getKey());
				continue;
			}
			if (last.getValue().equals(0d)) {
				t.remove(last.getKey());
				continue;
			}

			if (Math.abs(first.getValue()) > Math.abs(last.getValue())) {
				t.put(first.getKey(), first.getValue() + last.getValue());

				// System.out.println(first.getKey().getContactId() + " -> " +
				// last.getKey().getContactId() + " : " +
				// Math.abs(last.getValue()));
				payments.add(new Payment(first.getKey(), last.getKey(), Math
						.abs(last.getValue())));
				t.remove(last.getKey());
			} else {
				t.put(last.getKey(), first.getValue() + last.getValue());
				// System.out.println(first.getKey().getContactId() + " -> " +
				// last.getKey().getContactId() + " : " +
				// Math.abs(first.getValue()));
				payments.add(new Payment(first.getKey(), last.getKey(), Math
						.abs(first.getValue())));
				t.remove(first.getKey());
			}
		}
		return payments;
	}

	class ValueComparator implements Comparator {

		Map base;

		public ValueComparator(Map base) {
			this.base = base;
		}

		public int compare(Object lhs, Object rhs) {
			return ((Double) base.get(lhs)).compareTo((Double) base.get(rhs));
		}
	}

	public List<Payment> generateExpenseGraph(HashMap<Member, Double> balance) {

		List<MemberPay> membersPay = new LinkedList<MemberPay>();
		for (Map.Entry<Member, Double> member : balance.entrySet()) {
			membersPay.add(new MemberPay(member.getKey(), (double) member
					.getValue()));
		}

		Collections.sort(membersPay);
		Double[] amounts = new Double[membersPay.size()];

		for (int index = 0; index < amounts.length; index++) {
			amounts[index] = membersPay.get(index).balance;
		}

		List<Payment> payments = new LinkedList<Payment>();
		for (int index = 0; index < amounts.length; index++) {
			Member mem = membersPay.get(index).member;
			if (amounts[index] < 0) {
				double expense = amounts[index];

				Boolean[] res = SubSum.getMinSubSum(amounts, expense);
				for (int resIndex = 0; resIndex < res.length; resIndex++) {
					if (res[resIndex]) {
						payments.add(new Payment(mem, membersPay.get(resIndex).member,
								amounts[resIndex]));
						amounts[index] -= amounts[resIndex];
						amounts[resIndex] = 0.0;
					}
				}
			}
		}

		return payments;
	}

	private class MemberPay implements Comparable<MemberPay> {
		private Member member;
		private double balance;

		public MemberPay(Member member, double balance) {
			this.member = member;
			this.balance = balance;
		}

		public int compareTo(MemberPay another) {
			return Double.compare(this.balance, another.balance);
		}

	}
}
